<?php
//
class Router {
    /**
     * @var Router
     */
    static protected $instance; 
    /**
     * @var array
     */
    protected $routes, $webroot;
    
    protected function __construct() {}
    
    /**
     * 单例模式， 返回路由控制器
     * @return Router
     */
    static function &getInstance() {
        if (!isset(self::$instance)) {
            self::$instance = new Router();
        }
        return self::$instance;
    }
    
    static function url($url) {
        if (preg_match('#^[a-z]+\://#', $url)) {
            return $url;
        }
        if ($url && ('/' != $url[0])) {
            $url = '/'.$url;
        }
        $router = Router::getInstance();
        return $router->webroot.$url;
    }
    
    /**
     * 添加路由规则
     */
    static function add($route, $defaults = null) {
        $router = Router::getInstance();
        if (empty($route) || $route == '/') {
            return $router->routes[] = array($route, '~^[\/]*$~', array(), $defaults);
        } else {
            $elements = $router->filter(array_map('trim', explode('/', $route)));
            $names = array();
            foreach ($elements as $element) {
                if (preg_match('/^:(.+)$/', $element, $r)) {
                    $parsed[] = '(?:\/([^\/]+))?';
                    $names[] = $r[1];
                } elseif (preg_match('/^\*$/', $element, $r)) {
                    $parsed[] = '(?:\/(.*))?';
                } else {
                    $parsed[] = '/' . $element;
                }
            }
            $router->routes[] = array($route, '~^'.join('', $parsed).'[\/]*$~', $names, $defaults);
        }
    }
    
    /**
     * 解析URL所匹配的路由规则
     *
     * @param string $url
     * @return array
     */
    public function parse($url) {
        if ($url && ('/' != $url[0])) {
            $url = '/'.$url;
        }
        $this->webroot = preg_replace('#/[^/]+$#', '', $_SERVER['SCRIPT_NAME']);
        foreach ($this->routes as $route_name => $route) {
            list($route, $regexp, $names, $defaults) = $route;
            if (preg_match($regexp, $url, $r)) {
                array_shift($r);
                if (is_array($defaults)) {
                    foreach ($defaults as $name => $value) {
                        $out[$name] = $value;
                    }
                }

                $pos = 0;
                foreach ($r as $found) {
                    if (isset($names[$pos])) {
                        $out[$names[$pos]] = urldecode($found);
                    } else {
                        $pass = explode('/', $found);
                        $found = '';
                        for ($i = 0, $max = count($pass); $i < $max; $i+=2) {
                            if (!isset($pass[$i + 1])) continue;
                            
                            $found .= $pass[$i].'='.$pass[$i+1].'&';
                        }

                        parse_str($found, $pass);
                        foreach ($pass as $key => $value) {
                            $out[$key] = urldecode($value);
                        }
                    }
                    $pos++;
                }
                return $out;
            }
        }
    }
    
    protected function filter($var, $isArray = false) {
        if (is_array($var) && (!empty($var) || $isArray)) {
            return array_filter($var, array($this, 'filter'));
        } else {
            if ($var === 0 || $var === '0' || !empty($var)) {
                return true;
            } else {
                return false;
            }
        }
    }
}

